﻿/*****************************************介绍*****************************************
 * 作者：User
 * 创建时间：2025-03-31 18:42:13
 * 功能：游戏数据管理器
 *      管理所有游戏场景(非UI)相关数据
**************************************************************************************/

using Game.BaseData;
using Game.Framework;
using MessagePack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UnityEngine;

[CustomModule(12)]
public partial class GameDataMgr : BaseManager<GameDataMgr>, IModule
{
    private string m_GameDataPath;
    private GameDataModel m_GameDatas;
    private InitResult m_InitResult;
    private ETriggerAdType m_CurTriggerAdType;
    private Config m_Cfg;

    private GameDataMgr() { }

    void IModule.Init()
    {
        EventCenter.Instance.AddEventListen<bool>(EventName.MonoOnApplicationPause, OnApplicationPause);

        m_Cfg = BaseDataMgr.Instance.Cfg;
        m_GameDataPath = $"{Application.persistentDataPath}/GameData.dat";
        LogManager.Log($"game data path:{m_GameDataPath}", "GameDataMgr", "Init");

        m_InitResult = InitResult.Wait;
        if (!File.Exists(m_GameDataPath))
            CreateNewData();
        else
            InitLocalData();
        InitOtherData();

        m_InitResult.type = E_ResultType.Success;
    }

    private void OnApplicationPause(bool status)
    {
        Save();
    }

    InitResult IModule.GetInitResult() => m_InitResult;

    #region 初始化相关

    // 如果不是第一次进入游戏，则根据存档数据来初始化数据
    private void InitLocalData()
    {
        var buffer = File.ReadAllBytes(m_GameDataPath);
        m_GameDatas = MessagePackSerializer.Deserialize<GameDataModel>(buffer);
        LogManager.Log($"load local data", "GameData");
    }

    // 如果是第一次进入游戏，则根据基础数据来初始化数据
    private void CreateNewData()
    {
        m_GameDatas = new GameDataModel();
        m_GameDatas.allLevels = new Dictionary<int, GameDataModel.Level>();
        for (int i = 0; i < m_Cfg.level.level_data.Length; i++)
        {
            var lvInfo = m_Cfg.level.level_data[i];
            int reward = UnityEngine.Random.Range(lvInfo.rewards[0], lvInfo.rewards[1] + 1);
            string layout = m_Cfg.GetLayoutById(lvInfo.map[UnityEngine.Random.Range(0, lvInfo.map.Length)]);
            GameDataModel.Level lvData = new GameDataModel.Level(lvInfo.lv, layout, reward, lvInfo.type);
            m_GameDatas.allLevels.Add(lvData.level, lvData);
            if (lvData.level == 1)
                lvData.status = ELevelStatus.Unlocked;
        }
        m_GameDatas.curLevel = m_Cfg.level.level_data[0].lv;
        m_GameDatas.totalCoinsNum = m_Cfg.level.int_coins;

        // 创建地图数据
        m_GameDatas.maps = m_GameDatas.InitMap();
        LogManager.Log($"create new data", "GameData");
    }

    private void InitOtherData()
    {
        if (m_GameDatas.uid <= 0)
            m_GameDatas.uid = UnityEngine.Random.Range(100000, 1000000);

        //测试
        {
            // 清空内购数据
            //m_GameDatas.purchasedNonConsumableItems = null;

            //foreach (var item in m_GameDatas.maps.countries.Values)
            //{
            //    if (item.unlockedCities == null)
            //        item.unlockedCities = new List<string>();
            //    item.unlockedCities.Clear();
            //    if (item.cities != null)
            //    {
            //        foreach (var city in item.cities.Values)
            //        {
            //            if (city.isUnlocked)
            //                item.unlockedCities.Add(city.name);
            //        }
            //    }
            //}

            // 清空注册表数据
            //PlayerPrefs.DeleteAll();
        }

        LogManager.Log($"uid:{m_GameDatas.uid}", "GameDataMgr");
    }

    #endregion

    /// <summary>用户ID</summary>
    public int Uid => m_GameDatas.uid;

    /// <summary>激励广告总收益</summary>
    public double RewardAdTotalRevenue
    {
        get => m_GameDatas.rewardAdTotalRevenue;
        set
        {
            m_GameDatas.rewardAdTotalRevenue = value;
            Save();
        }
    }

    /// <summary>插屏广告总收益</summary>
    public double IntAdTotalRevenue
    {
        get => m_GameDatas.intAdTotalRevenue;
        set
        {
            m_GameDatas.intAdTotalRevenue = value;
            Save();
        }
    }

    /// <summary>开屏广告总收益</summary>
    public double OpenAdTotalRevenue
    {
        get => m_GameDatas.openAdTotalRevenue;
        set
        {
            m_GameDatas.openAdTotalRevenue = value;
            Save();
        }
    }

    /// <summary>横幅广告总收益</summary>
    public double BannerAdTotalRevenue
    {
        get => m_GameDatas.bannerAdTotalRevenue;
        set
        {
            m_GameDatas.bannerAdTotalRevenue = value;
            Save();
        }
    }

    /// <summary>是否还原商品成功</summary>
    public bool IsResotred
    {
        get => m_GameDatas.isResotred;
        set
        {
            m_GameDatas.isResotred = value;
            Save();
        }
    }

    public bool MusicSwitch
    {
        get => m_GameDatas.musicSwitch;
        set
        {
            m_GameDatas.musicSwitch = value;
        }
    }

    public bool SoundSwitch
    {
        get => m_GameDatas.soundSwitch;
        set
        {
            m_GameDatas.soundSwitch = value;
        }
    }

    public bool VibrationSwitch
    {
        get => m_GameDatas.vibrationSwitch;
        set
        {
            m_GameDatas.vibrationSwitch = value;
        }
    }

    public long TotalStarNum => m_GameDatas.totalStarNum;

    public long TotalCoinsNum => m_GameDatas.totalCoinsNum;

    public int CurLevel
    {
        get => m_GameDatas.curLevel;
        set
        {
            if (m_GameDatas.curLevel != value)
            {
                m_GameDatas.curLevel = value;

                if (value > m_Cfg.level.level_data.Length)
                {
                    var lvInfo = m_Cfg.level.other_level;
                    string layout = m_Cfg.GetLayoutById(lvInfo.map[UnityEngine.Random.Range(0, lvInfo.map.Length)]);
                    int raward = UnityEngine.Random.Range(lvInfo.rewards[0], lvInfo.rewards[1] + 1);
                    GameDataModel.Level lvData = new GameDataModel.Level(value, layout, raward, lvInfo.type);
                    m_GameDatas.allLevels.Add(lvData.level, lvData);
                }

                // 处理等级状态
                m_GameDatas.allLevels[value].status = ELevelStatus.Unlocked;

                // 处理图片缓存
                var curLvData = GetLevel(value);
                if (curLvData.assetsInfo == null)
                {
                    var unusedCaches = GetUnusedCache();
                    curLvData.assetsInfo = new List<GameDataModel.AssetInfo>();

                    foreach (var item in unusedCaches)
                    {
                        curLvData.assetsInfo.Add(item.Value.Clone());
                        if (curLvData.assetsInfo.Count >= 4)
                            break;
                    }

                    // 如果前面缓存的内容不够用了，就走这里处理
                    int needCount = 4 - curLvData.assetsInfo.Count;
                    for (int i = 4 - needCount; i < 4; i++)
                    {
                        curLvData.assetsInfo.Add(new GameDataModel.AssetInfo());
                        AssetCache.CacheSingleSmallImg(curLvData, i, null);
                    }
                }

                EventCenter.Instance.Trigger(GameEventName.OnCurLevelChanged, value);
                NativeInteraction.Instance.SendUserProperty();
            }
        }
    }

    public int HintRemainCount
    {
        get => m_GameDatas.hintRemainCount;
        set
        {
            if (m_GameDatas.hintRemainCount != value)
            {
                m_GameDatas.hintRemainCount = value;
                EventCenter.Instance.Trigger(GameEventName.OnHintCountChanged, value);
                Save();
            }
        }
    }

    public int BombRemainCount
    {
        get => m_GameDatas.bombRemainCount;
        set
        {
            if (m_GameDatas.bombRemainCount != value)
            {
                m_GameDatas.bombRemainCount = value;
                EventCenter.Instance.Trigger(GameEventName.OnBombCountChanged, value);
                Save();
            }
        }
    }

    public int ShuffleRemainCount
    {
        get => m_GameDatas.shuffleRemainCount;
        set
        {
            if (m_GameDatas.shuffleRemainCount != value)
            {
                m_GameDatas.shuffleRemainCount = value;
                EventCenter.Instance.Trigger(GameEventName.OnShuffleCountChanged, value);
                Save();
            }
        }
    }

    public int AddTimeRemainCount
    {
        get => m_GameDatas.addTimeRemainCount;
        set
        {
            if (m_GameDatas.addTimeRemainCount != value)
            {
                m_GameDatas.addTimeRemainCount = value;
                EventCenter.Instance.Trigger(GameEventName.OnAddTimeCountChanged, value);
                Save();
            }
        }
    }

    public bool IsNoFirstEnterGame
    {
        get => m_GameDatas.isNoFirstEnterGame;
        set
        {
            m_GameDatas.isNoFirstEnterGame = value;
            Save();
        }
    }

    public GameDataModel.AssetInfo CurHallBgInfo
    {
        get => m_GameDatas.curHallBgInfo;
        set
        {
            m_GameDatas.curHallBgInfo = value;
            EventCenter.Instance.Trigger(GameEventName.OnChangedHallBg, value);
            Save();
        }
    }

    /// <summary>
    /// 触发广告的类型
    /// <para>注意：每次在触发广告前需要设置该值，关闭广告或者播放广告失败后需要重置该值为None</para>
    /// </summary>
    public ETriggerAdType TriggerAdType
    {
        get => m_CurTriggerAdType;
        set => m_CurTriggerAdType = value;
    }

    public GameDataModel.Level GetLevel(int level)
    {
        if (m_GameDatas.allLevels.ContainsKey(level))
            return m_GameDatas.allLevels[level];
        return null;
    }

    public void UpdateCoins(int increment)
    {
        var old = m_GameDatas.totalCoinsNum;
        m_GameDatas.totalCoinsNum += increment;
        EventCenter.Instance.Trigger(GameEventName.OnPlayerCoinsChanged, old, m_GameDatas.totalCoinsNum);
        Save();
        NativeInteraction.Instance.SendUserProperty();
    }

    public void UpdateStar(int increment)
    {
        var old = m_GameDatas.totalStarNum;
        m_GameDatas.totalStarNum += increment;
        EventCenter.Instance.Trigger(GameEventName.OnPlayerStarChanged, old, m_GameDatas.totalStarNum);
        Save();
        NativeInteraction.Instance.SendUserProperty();
    }

    public bool IsUnlockHint() => m_GameDatas.curLevel >= m_Cfg?.props.hint.unlock;
    public bool IsUnlockBomb() => m_GameDatas.curLevel >= m_Cfg?.props.bomb.unlock;
    public bool IsUnlockShuffle() => m_GameDatas.curLevel >= m_Cfg?.props.shuffle.unlock;
    public bool IsUnlockTime() => m_GameDatas.curLevel >= m_Cfg?.props.time.unlock;
    public bool IsUnlockErrorLimit() => m_GameDatas.curLevel >= m_Cfg?.props.error.unlock;
    public bool IsUnlockTimeLimit() => m_GameDatas.curLevel >= m_Cfg?.props.timeLimit.unlock;

    /// <summary>获取未使用的所有缓存</summary>
    public Dictionary<int, GameDataModel.AssetInfo> GetUnusedCache()
    {
        // 检查前面关卡选择的图片，确保复用没用到的缓存
        var used = new Dictionary<int, GameDataModel.AssetInfo>();
        var unusedAssets = new Dictionary<int, GameDataModel.AssetInfo>();
        foreach (var level in m_GameDatas.allLevels.Values)
        {
            if (level.assetsInfo == null || level.finalSelectIdx == -1) continue;
            var info = level.assetsInfo[level.finalSelectIdx];
            used.TryAdd(info.id, info);
        }

        foreach (var level in m_GameDatas.allLevels.Values)
        {
            if (level.assetsInfo == null || level.finalSelectIdx == -1) continue;
            for (int i = 0; i < level.assetsInfo.Count; i++)
            {
                if (used.ContainsKey(level.assetsInfo[i].id)) continue;
                unusedAssets.TryAdd(level.assetsInfo[i].id, level.assetsInfo[i]);
            }
        }
        return unusedAssets;
    }

    /// <summary>所有关卡信息</summary>
    public Dictionary<int, GameDataModel.Level> AllLevelsInfo => m_GameDatas.allLevels;

    #region 地图相关

    public GameDataModel.Map MapInfo => m_GameDatas.maps;

    #endregion

    #region 商品相关

    /// <summary>购买器</summary>
    public Purchase Purchase { get; set; }

    /// <summary>判断当前用户是否已经购买了指定的非消耗型道具</summary>
    public bool IsPurchaseItem(string id)
    {
        return m_GameDatas.purchasedNonConsumableItems != null && m_GameDatas.purchasedNonConsumableItems.ContainsKey(id);
    }

    /// <summary>添加已经购买的非消耗型道具</summary>
    public void AddPurchasedNonConsumableItem(string id)
    {
        if (m_GameDatas.purchasedNonConsumableItems == null)
            m_GameDatas.purchasedNonConsumableItems = new Dictionary<string, long>();
        if (!m_GameDatas.purchasedNonConsumableItems.ContainsKey(id))
        {
            m_GameDatas.purchasedNonConsumableItems.Add(id, DateTime.Now.Ticks);
            Save();
        }
    }

    public bool IsPurchased_RemoveAds() => IsPurchaseItem(ProductName.Remove_ads);

    #endregion

    void IModule.Clear()
    {
        Save();
        EventCenter.Instance.RemoveEventListen<bool>(EventName.MonoOnApplicationPause, OnApplicationPause);
    }

    public void Save()
    {
        ThreadPool.QueueUserWorkItem((data) =>
        {
            // 将数据保存到本地
            if (m_GameDatas == null) return;
            var safeOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.TrustedData);
            byte[] buffer = MessagePackSerializer.Serialize(m_GameDatas, safeOptions);
            if (!File.Exists(m_GameDataPath))
            {
                string dir = Path.GetDirectoryName(m_GameDataPath);
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
            }
            File.WriteAllBytes(m_GameDataPath, buffer);
            LogManager.Log($"save game data， len:{buffer.Length} data:{string.Join("-", buffer)}", "GameDataMgr");
        });

    }
}